/**
 * AGNAngularParameterHandle.java
 */

package agngui.agnmodel;
import javax.media.j3d.PickRay;
import javax.media.j3d.Transform3D;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;

/**
 * This class is for handles that rotate along an axis
 */
public class AGNAngularParameterHandle extends AGNParameterHandle {
    /**
     * AGNAngularParameterHandle
     * 
     * Initialize this angular parameter handle object
     *
     * @param object     The object that owns this handle
     * @param point      The point (in world space) that the handle currently lies on
     * @param axis       The axis about which this point rotates
     * @param identifier The parameer identifier (depends on the AGNObject this handle belongs to)
     */
    public AGNAngularParameterHandle( AGNObject object, Point3d point, Vector3d axis, String identifier ) {
        super( AGNParameterHandle.TYPE_ANGULAR, object, point, axis, identifier );
        recentValue = 0;
    }

    /**
     * calculateNewValueFromWorldLocation
     *
     * Calculates the new handle value based on the world point passed, and
     * stores the most recent value internally.
     *
     * @param worldPoint The point in world space projected by
     *                   projectClickOntoControlAxis
     * @return The calculated value (depends on handle type)
     */
    public double calculateNewValueFromWorldLocation( Point3d worldPoint ) {
        Transform3D transform = new Transform3D();
        Vector3d    newVector = new Vector3d( worldPoint );
        Vector3d    up        = new Vector3d( 0.0, 0.0, 1.0 );

        transform = object.getFullTransform();
		transform.setScale(AGNObject.ONE_DISTANCE_UNIT);

        transform.transform( up );

        newVector.normalize();
        up.normalize();

        recentValue = newVector.dot( up );
        recentValue = Math.acos( recentValue );

        return recentValue;
    }    

    /**
     * projectClickOntoControlAxis
     *
     * Projects a mouse click onto the actual control axis in world space and
     * gets the screen-space intersection point.
     *
     * @param mX The mouse click x-coordinate
     * @param mY The mouse click y-coordinate
     * @param renderer The model renderer, needed for camera access and projection
     * @return The point in world-space of the finally projected point
     */
    public Point3d projectClickOntoControlAxis( int mX, int mY, AGNModelRenderer renderer ) {
        PickRay     ray;

        Vector3d rayDir       = new Vector3d();
        Vector3d pointVector  = new Vector3d( point );
        Vector3d controlAxis  = new Vector3d( axis );
        Vector3d planeNormal  = new Vector3d();
		Vector3d lookAtVector = new Vector3d();
        Vector3d clickVector  = new Vector3d();
        Point3d  clickPoint   = new Point3d();
        Point3d  rayOrigin    = new Point3d();
        double   D;
        double   t;
        double   Vd;

        // The plane normal is the axis of rotation
        planeNormal.set( controlAxis );
        planeNormal.normalize(); 
		
		lookAtVector.sub(renderer.getCamera().getLocation(), renderer.getCamera().getLookAt());
		lookAtVector.normalize();

        // Get the point of the mouse click in world space via ray-plane intersection
        ray = renderer.getClickRay( mX, mY );
        ray.get( rayOrigin, rayDir );
        Vd = planeNormal.dot( rayDir );

        D = -planeNormal.dot( new Vector3d( point ) );
        t = -(planeNormal.dot( new Vector3d( rayOrigin )) + D) / Vd;

        if( t < 0 ) {
        	// Plane is behind the camera? Shouldn't be possible
        }

        rayDir.scale( t );
        clickPoint.add( rayOrigin, rayDir );

        // Project the point onto the rotational circle
        clickVector.set( clickPoint );
        clickVector.normalize();
        clickVector.scale( pointVector.length() );

        return new Point3d( clickVector ); 
    }
}

